export interface ComponentOptions {
    name?: string;
    template: string;
    data?: () => Record<string, any>;
    methods?: Record<string, Function>;
    computed?: Record<string, Function>;
    watch?: Record<string, (newVal: any, oldVal: any) => void>;
    components?: Record<string, ComponentOptions>;
    props?: Record<string, any>;
    provide?: Record<string, any>;
    inject?: string[];
    directives?: Record<string, any>;
    inheritAttrs?: boolean;
}

type LifecycleHook = 'beforeMount' | 'mounted' | 'beforeUpdate' | 'updated' | 'beforeDestroy' | 'destroyed';

export class Component {
    public name?: string;
    public template: string;
    public data: Record<string, any>;
    public methods: Record<string, Function>;
    public computed: Record<string, Function>;
    public watch: Record<string, (newVal: any, oldVal: any) => void>;
    public components: Record<string, ComponentOptions>;
    public props: Record<string, any>;
    public provide: Record<string, any>;
    public inject: string[];
    public directives: Record<string, any>;
    public inheritAttrs: boolean;
    private isMounted = false;

    // 新增 rootElement 属性，用于缓存挂载的根节点
    private rootElement: HTMLElement | null = null;

    constructor(options: ComponentOptions) {
        // 初始化组件选项
        this.name = options.name;
        this.template = options.template;
        this.data = this.makeReactive(options.data ? options.data() : {});
        this.methods = options.methods || {};
        this.computed = options.computed || {};
        this.watch = options.watch || {};
        this.components = options.components || {};
        this.props = options.props || {};
        this.provide = options.provide || {};
        this.inject = options.inject || [];
        this.directives = options.directives || {};
        this.inheritAttrs = options.inheritAttrs ?? true;

        // 执行 beforeMount 生命周期钩子
        this.callHook('beforeMount');
        this.isMounted = true;
    }

    /**
     * 渲染组件模板，生成并返回一个新的根元素
     */
    protected render(): HTMLElement {
        // 使用虚拟容器解析 HTML 模板
        const container = document.createElement('div');
        container.innerHTML = this.compileTemplate(this.template);

        // 提取模板的第一个子元素作为根元素
        const rootElement = container.firstElementChild as HTMLElement;

        if (rootElement) {
            // 递归绑定事件
            this.bindEventsRecursively(rootElement);
        }

        return rootElement;
    }

    /**
     * 递归绑定事件到模板中的每个元素
     */
    private bindEventsRecursively(element: HTMLElement) {
        // 处理自身的事件绑定
        this.bindEvents(element);

        // 递归处理子元素的事件绑定
        element.querySelectorAll('*').forEach(child => this.bindEvents(child as HTMLElement));
    }

    /**
     * 检查元素上以 @ 开头的事件属性并绑定对应方法
     */
    private bindEvents(element: HTMLElement) {
        Array.from(element.attributes).forEach(attr => {
            if (attr.name.startsWith('@')) {
                // 获取事件名称和方法名
                const eventName = attr.name.slice(1);
                const methodName = attr.value;

                // 检查方法是否存在于 methods 中
                if (this.methods[methodName]) {
                    // 绑定事件
                    element.addEventListener(eventName, this.methods[methodName].bind(this));
                }

                // 绑定后移除自定义属性
                element.removeAttribute(attr.name);
            }
        });
    }

    /**
     * 编译模板，将 {{ }} 中的变量替换成 data 中的值
     */
    private compileTemplate(template: string): string {
        return template.replace(/\{\{(.+?)\}\}/g, (_, expression) => {
            try {
                const fn = new Function('data', 'with(data) { return ' + expression.trim() + '; }');
                return fn(this.data);
            } catch (e) {
                console.warn('Template expression error:', e);
                return '';
            }
        });
    }

    /**
     * 挂载组件到指定的 DOM 元素
     */
    mount(selector: string) {
        const element = document.querySelector(selector);
        if (element) {
            // 将渲染的根元素缓存到 rootElement，以便后续更新
            this.rootElement = this.render();
            element.appendChild(this.rootElement);
            this.callHook('mounted');
        }
    }

    /**
     * 在数据变化时更新根节点内容而不替换整个 DOM
     */
    private update() {
        if (this.rootElement) {
            // 替换 rootElement 内容，保留节点引用
            const newRoot = this.render();
            this.rootElement.replaceWith(newRoot);
            this.rootElement = newRoot;  // 更新 rootElement 的引用
        }
    }

    /**
     * 创建数据代理对象，以实现数据变化时触发更新
     */
    private makeReactive(data: Record<string, any>) {
        return new Proxy(data, {
            get: (target: any, key: string) => {
                return target[key];
            },
            set: (target: any, key: string, value: any) => {
                // 如果值相等 不做处理
                if (target[key] === value) return true;

                const oldValue = target[key];
                target[key] = value;

                // 数据变化时触发更新
                this.callHook('beforeUpdate');
                this.update();
                this.callHook('updated');

                // 如果定义了 watch 对应的属性，调用监听回调
                if (this.watch[key]) {
                    this.watch[key].call(this, value, oldValue);
                }
                return true;
            }
        });
    }

    // 生命周期钩子
    protected beforeMount() {}
    protected mounted() {}
    protected beforeUpdate() {}
    protected updated() {}
    protected beforeDestroy() {}
    protected destroyed() {}

    /**
     * 调用指定的生命周期钩子
     */
    private callHook(hook: LifecycleHook) {
        if (typeof this[hook] === 'function') {
            (this[hook] as Function).call(this);
        }
    }

    /**
     * 销毁组件，调用生命周期钩子
     */
    public destroy() {
        this.callHook('beforeDestroy');
        this.callHook('destroyed');
    }
}
